import uniqueId from "../uniqueId.ts";
import { ref, watch, reactive } from 'vue';
import { GetExpectList, TransformBabel } from "./js-loader.esm.js";
import { minify } from "terser";
import MouseEvent from './MouseEvent.ts'
import JSONHistory from "./History.ts";
import Hotkey from './Hotkey.ts'

interface ParentItem {
    name: string,
    icon: string,
    id: string
}
interface MouseMoveCache {
    x: number,
    y: number,
    name: string,
    icon: string
}

// 默认代码块
let DefaultCode = `/**
* 尊敬的用户，你好：页面 JS 面板是高阶用法，一般不建议普通用户使用，
* 如需使用，请确定你具备研发背景，能够自我排查问题。
*/

// 用于获取全局 数据源数据
import State from "cache-state";

// 用于获取全局 表单数据
import Value from "cache-value";

// 用于获取全局方法
import Utils from "Utils";

// 用于获取当前页面 vue 实例
import VueView from "vue-view"

/**
 * 当页面渲染完毕后马上调用下面的函数。
 */
export function onMountedEvent() {

}
`;


/**
 * 编辑模式控制模块
 *
 * @export
 * @class DocumentEditor
 */
export default class DocumentEditor {
    Rules: any = {}
    State: string = 'Edit'

    RuleMapping: any = reactive({})
    CellMapping: any = reactive({})
    WillUploadFileMapping: any = {}

    MoveState = ref<boolean>(false)

    ParentList = ref<Array<ParentItem>>([])
    ActiveRect = ref<null | DOMRect>()
    ActiveId = ref<null | string>(null)

    HoverRect = ref<null | DOMRect>(null)
    HoverItemId = ref<null | string>(null)

    DragMarkRect = ref<null | DOMRect>(null)
    IndicateRect = ref<null | DOMRect>(null)
    IndicateType = ref<null | string>(null)
    IndicateId = ref<null | string>(null)

    MouseMoveCache = ref<MouseMoveCache>({ x: 0, y: 0, name: '', icon: '' });

    WatchCache = []

    CacheData = ref({
        DataSet: [{ type: "url", title: "URLParams", id: "dy9962u4c57sr" }],
        Code: DefaultCode, // 代码缓存
        BabelCode: '', // 执行缓存代码
        JsonCode: [],
        Rules: { modal: [], page: [], }, // 规则缓存
        Ele: {},
        ColorCache: [],
    })
    ElementCache = {}
    CommonFunctionKeys = ref([])
    SetColorCache(Color) {
        var colors = this.CacheData.value.ColorCache;
        if (!colors.includes(Color)) {
            this.CacheData.value.ColorCache.push(Color);
        }
    }
    DeleteColorCache(index) {
        this.CacheData.value.ColorCache.splice(index, 1);
    }
    /**
     * 加载元件
     *
     * @param {*} Rule
     * @memberof DocumentEditor
     */
    SetRule(Rule) {
        this.Rules = Rule;
    }

    /**
     * 缓存组件的 vnode
     *
     * @param {*} key
     * @param {*} value
     * @memberof DocumentEditor
     */
    SetEle(key, value) {
        this.ElementCache[key] = value;
    }

    /**
     * 获取缓存中的引用元素
     *
     * @param {*} key
     * @return {*} 
     * @memberof DocumentEditor
     */
    GetEle(key) {
        return this.ElementCache[key]?.el
    }
    /**
     * 给界面赋值
     *
     * @param {*} value
     * @memberof DocumentEditor
     */
    SetData(value) {
        this.CacheData.value = value;
        this.RuleMapping = reactive({});
        var RenderChild = (cells, parent, slotkey) => {
            for (let i = 0; i < cells.length; i++) {
                const element = cells[i];
                const DefaultRules = this.Rules[element.type].Rule.rule();
                // 当属性中没有默认值时, 合并默认值
                for (const key in DefaultRules) {
                    if (!element[key]) {
                        element[key] = DefaultRules[key]
                    }
                }
                this.RuleMapping[element.field] = element;
                element._parent = parent;
                element._slotkey = slotkey;
                for (const key in element.slots) {
                    const item = element.slots[key];
                    if (item.length && item.length > 0) {
                        RenderChild(item, element.field, key);
                    };
                }
            }
        }
        RenderChild(this.CacheData.value.Rules.page, null, null);
        RenderChild(this.CacheData.value.Rules.modal, null, null);
        // this.FormatCode();
    }

    /**
     * 格式化代码
     *
     * @memberof DocumentEditor
     */
    FormatCode() {
        GetExpectList(this.CacheData.value.Code).then((res) => {
            this.CommonFunctionKeys.value = res;
        });
        TransformBabel(this.CacheData.value.Code).then((res) => {
            minify(res).then((output) => {
                this.CacheData.value.BabelCode = output as string;
            });
        });
    }
    Hotkey = new Hotkey()
    HistoryEvent = new JSONHistory(this)
    MouseEvent = new MouseEvent(this)
    constructor() {

        this.WatchCache.push(watch(this.ActiveId, val => {
            // this.ActiveId.value = val;
            this.ParentList.value = [];
            if (val != null && this.RuleMapping[val]) {
                const _ele = this.GetEle(val);
                this.ActiveRect.value = _ele?.getBoundingClientRect();
                const CellRule = this.GetRuleById(val);
                this.EachParent(CellRule, (item) => {
                    this.ParentList.value.push({
                        name: item?.props?.title || this.Rules[item.type].Rule.name,
                        icon: this.Rules[item.type].Rule.icon,
                        id: item.field
                    });
                })
            }
        }));

        this.WatchCache.push(watch(this.HoverItemId, val => {
            this.HoverItemId.value = val;
            if (val != null && this.RuleMapping[val]) {
                const _ele = this.GetEle(val);
                this.HoverRect.value = _ele?.getBoundingClientRect();
            } else {
                this.HoverRect.value = null;
            }
        }));

        this.WatchCache.push(watch(this.CacheData, val => {
            this.HistoryEvent.SetData(val)
        }, { deep: true }));



        // 撤回
        this.Hotkey.addHotkey('Ctrl+Z', () => { this.HistoryEvent.Undo(); })
        // 重做
        this.Hotkey.addHotkey('Ctrl+Shift+Z', () => { this.HistoryEvent.Redo(); })
        // 复制
        this.Hotkey.addHotkey('Ctrl+C', () => { this.HotKeyCopy(); })
        // 粘贴
        this.Hotkey.addHotkey('Ctrl+V', () => { this.HotKeyPaste(); })
        // 剪切
        this.Hotkey.addHotkey('Ctrl+X', () => { this.HotKeyCut(); })
        // 选择父级 
        this.Hotkey.addHotkey('ArrowUp', () => { this.HotKeySelectParent(); })
        // 选择子集节点 
        this.Hotkey.addHotkey('ArrowDown', () => { this.HotKeySelectChild(); })
        // 选择子集节点 
        this.Hotkey.addHotkey('ArrowLeft', () => { this.HotKeySelectLeft(); })
        // 选择子集节点 
        this.Hotkey.addHotkey('ArrowRight', () => { this.HotKeySelectRight(); })
        // 保存
        this.Hotkey.addHotkey('Ctrl+S', () => {
            console.log(JSON.stringify(this.CacheData.value.Rules, null, '  '))
        }, {}, true)
        // 删除节点
        this.Hotkey.addHotkey('Delete', () => { this.HotKeyDelete(); })
        this.Hotkey.addHotkey('BackSpace', () => { this.HotKeyDelete(); })
        // console.log(this.Hotkey)
    }
    /**
     * 刷新界面焦点元素(在滚动条滚动时触发)
     *
     * @memberof DocumentEditor
     */
    RefreshActiveBoard() {
        if (this.ActiveId.value) {
            var _ele = this.GetEle(this.ActiveId.value);
            this.ActiveRect.value = _ele?.getBoundingClientRect();
        } else {
            this.ActiveRect.value = null
        };

        if (this.MouseEvent.MouseDownCache) {
            var _ele = this.GetEle(this.MouseEvent.MouseDownCache);
            this.DragMarkRect.value = _ele?.getBoundingClientRect();
        } else {
            this.DragMarkRect.value = null;
        }

        this.IndicateRect.value = null;
        this.IndicateId.value = null;
        // DragMarkRect
        this.HoverRect.value = null;
        this.MouseEvent.RefreshHoverId();
    }
    /**
     * 当前元素是否是焦点元素的子元素
     *
     * @param {string} id
     * @return {boolean} 
     * @memberof DocumentEditor
     */
    IsActiveChild(id: string): boolean {
        let ans = false;
        const Rule = this.GetRuleById(id);
        this.EachParent(Rule, (parent) => {
            if (this.ActiveId.value == parent.field) {
                ans = true;
                return false
            }
        });
        return ans;
    }
    AddSlot(AddType: string, ToId: string, slotKey: string, slotTitle: string) {
        const AddRule = this.GetRuleType(AddType).rule();
        AddRule.title = slotTitle;
        const ToRule = this.GetRuleById(ToId);
        ToRule.slots[slotKey] = [];
        ToRule.slots[slotKey].push(AddRule);

        var RenderChild = (cell, parent, SlotKey) => {
            this.RuleMapping[cell.field] = cell;
            // this.StyleEvent.ChangeStyle(cell.field, cell.style)
            cell._parent = parent;
            cell._slotkey = SlotKey;
            for (const key in cell.slots) {
                const element = cell.slots[key];
                for (let i = 0; i < element.length; i++) {
                    const child = element[i];
                    RenderChild(child, cell.field, key);
                }
            }
        };
        RenderChild(AddRule, ToId, slotKey);
    }
    /**
     * 创建元件
     *
     * @param {string} AddType
     * @param {string} ToId
     * @param {string} MoveState
     * @memberof DocumentEditor
     */
    AddItem(AddType: string, ToId: string, MoveState: string) {
        const AddRule = this.GetRuleType(AddType).rule();
        var RenderChild = (cell, parent, SlotKey) => {
            this.RuleMapping[cell.field] = cell;
            // this.StyleEvent.ChangeStyle(cell.field, cell.style)
            cell._parent = parent;
            cell._slotkey = SlotKey;
            for (const key in cell.slots) {
                const element = cell.slots[key];
                for (let i = 0; i < element.length; i++) {
                    const child = element[i];
                    RenderChild(child, cell.field, key);
                }
            }
        };
        const ToRule = this.GetRuleById(ToId);
        if (MoveState == 'IN') {
            ToRule.slots.default.push(AddRule);
            RenderChild(AddRule, ToId, 'default');
        } else {
            let index = (MoveState == 'RIGHT' || MoveState == 'DOWN') ? 1 : 0;
            const ToSlotKey = ToRule._slotkey || 'default';
            const ToParentRule = this.GetRuleById(ToRule._parent);
            for (let i = 0; i < ToParentRule.slots[ToSlotKey].length; i++) {
                const element = ToParentRule.slots[ToSlotKey][i];
                if (element.field == ToId) {

                    ToParentRule.slots[ToSlotKey].splice(i + index, 0, AddRule);
                    RenderChild(AddRule, ToParentRule.field, ToSlotKey);
                    break;
                }
            }
        }

        setTimeout(() => {
            this.ActiveId.value = AddRule.field
        }, 1)

    }

    /**
     * 元件移动位置
     *
     * @param {string} FormId
     * @param {string} ToId
     * @param {string} MoveState
     * @memberof DocumentEditor
     */
    MoveItem(FormId: string, ToId: string, MoveState: string, isCopy = false) {
        const MoveRule = this.GetRuleById(FormId);
        let FormRule

        if (isCopy) {
            var Copydata = JSON.parse(JSON.stringify(MoveRule))
            this.CopyEvent(Copydata);
            FormRule = Copydata;
        } else {
            FormRule = this.GetRuleById(FormId);
            const FormSlotKey = FormRule._slotkey || 'default';
            const FormParentRule = this.GetRuleById(FormRule._parent);
            for (let i = 0; i < FormParentRule.slots[FormSlotKey].length; i++) {
                const element = FormParentRule.slots[FormSlotKey][i];
                if (element.field == FormId) {
                    FormParentRule.slots[FormSlotKey].splice(i, 1);
                    break;
                }
            }
        }


        const ToRule = this.GetRuleById(ToId);
        if (MoveState == 'IN') {
            FormRule._slotkey = 'default';
            FormRule._parent = ToId;
            ToRule.slots.default.push(FormRule);
        } else {
            let index = (MoveState == 'RIGHT' || MoveState == 'DOWN') ? 1 : 0;
            const ToSlotKey = ToRule._slotkey || 'default';
            const ToParentRule = this.GetRuleById(ToRule._parent);
            for (let i = 0; i < ToParentRule.slots[ToSlotKey].length; i++) {
                const element = ToParentRule.slots[ToSlotKey][i];
                if (element.field == ToId) {
                    FormRule._slotkey = ToSlotKey;
                    FormRule._parent = ToParentRule.field;
                    ToParentRule.slots[ToSlotKey].splice(i + index, 0, FormRule);
                    break;
                }
            }
        }
    }
    /**
     * 删除元素
     *
     * @param {string} id
     * @memberof DocumentEditor
     */
    DeleteItem(id: string) {
        const Rule = this.GetRuleById(id);
        const SlotKey = Rule._slotkey || 'default';
        const ParentRule = this.GetRuleById(Rule._parent);
        for (let i = 0; i < ParentRule.slots[SlotKey].length; i++) {
            const element = ParentRule.slots[SlotKey][i];
            if (element.field == id) {
                ParentRule.slots[SlotKey].splice(i, 1);
                this.ActiveId.value = null;
                break;
            }
        };
    }

    /**
     * 复制规则对象
     *
     * @param {*} Rule
     * @return {*} 
     * @memberof DocumentEditor
     */
    CopyEvent(Rule, NewField = true) {
        NewField && (Rule.field = uniqueId());
        this.RuleMapping[Rule.field] = Rule;
        for (const key in Rule.slots) {
            const element = Rule.slots[key];
            for (let i = 0; i < element.length; i++) {
                const item = element[i];
                item._parent = Rule.field;
                this.CopyEvent(item, NewField)
            }
        }
        return Rule.field;
    }
    /**
     * 复制元件
     *
     * @param {string} id
     * @memberof DocumentEditor
     */
    CopyItem(id: string) {
        const Rule = this.GetRuleById(id);
        const SlotKey = Rule._slotkey || 'default';
        const ParentRule = this.GetRuleById(Rule._parent);
        const _Rule = JSON.parse(JSON.stringify(Rule))
        var _id = this.CopyEvent(_Rule);
        for (let i = 0; i < ParentRule.slots[SlotKey].length; i++) {
            const element = ParentRule.slots[SlotKey][i];
            if (element.field == id) {
                ParentRule.slots[SlotKey].splice(i + 1, 0, _Rule);
                setTimeout(() => {
                    this.ActiveId.value = _id;
                }, 10)
                break;
            }
        };
    }
    HotKeyCacheData = null;
    HotKeyState = null;
    /**
     * 判断是否执行快捷键操作
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    CheckInputFocusStatus() {
        let state = false;
        const inputs = document.querySelectorAll('input');
        for (let i = 0; i < inputs.length; i++) {
            if (inputs[i] === document.activeElement) {
                state = true;
                break;
            }
        };
        // 判断结束，有焦点直接中断
        if (state) {
            return state
        }
        // 没有焦点向下判断 textarea
        const textareas = document.querySelectorAll('textarea');
        for (let i = 0; i < textareas.length; i++) {
            if (textareas[i] === document.activeElement) {
                state = true;
                break;
            }
        };
        return state;
    }

    /**
     * 快捷键复制
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeyCopy() {
        if (this.CheckInputFocusStatus()) return;
        if (!this.ActiveId.value) return;
        const id = this.ActiveId.value;
        const RuleConfig = this.GetRuleConfigById(id);
        if (RuleConfig.Tools.Copy === false) {
            this.HotKeyCacheData === null
            return
        };
        const Rule = this.GetRuleById(id);
        this.HotKeyCacheData = JSON.parse(JSON.stringify(Rule));
        this.HotKeyState = 'Copy';
    }

    /**
     * 快捷键剪切
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeyCut() {
        if (this.CheckInputFocusStatus()) return;
        if (!this.ActiveId.value) return;
        const id = this.ActiveId.value;
        const Rule = this.GetRuleById(id);
        this.HotKeyCacheData = JSON.parse(JSON.stringify(Rule));
        this.DeleteItem(id);
        this.HotKeyState = 'Cut';
    }

    /**
     * 快捷键粘贴
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeyPaste() {
        if (this.CheckInputFocusStatus()) return;
        if (this.HotKeyCacheData === null) return;
        const id = this.ActiveId.value;
        if (!id) return;
        const RuleConfig = this.GetRuleConfigById(id);
        const Rule = this.GetRuleById(id);
        const _Rule = JSON.parse(JSON.stringify(this.HotKeyCacheData))

        this.CopyEvent(_Rule, this.HotKeyState == 'Copy');
        if (RuleConfig.DragType == 'OnlyIn') {
            _Rule._slotkey = 'default';
            _Rule._parent = id;
            Rule.slots.default.push(_Rule);
        } else {
            const ParentRule = this.GetRuleById(Rule._parent);
            for (let i = 0; i < ParentRule.slots['default'].length; i++) {
                const element = ParentRule.slots['default'][i];
                if (element.field == id) {
                    _Rule._slotkey = 'default';
                    _Rule._parent = ParentRule.field;
                    ParentRule.slots['default'].splice(i + 1, 0, _Rule);
                    break;
                }
            };
        };
        if (this.HotKeyState == 'Cut') {
            this.HotKeyCacheData = null;
            this.HotKeyState = null;
        }

        setTimeout(() => {
            this.ActiveId.value = _Rule.field;
        }, 10)
    }

    /**
     * 快捷键 选择父级
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeySelectParent() {
        if (this.CheckInputFocusStatus()) return;
        if (!this.ActiveId) return;
        const ActiveRule = this.GetRuleById(this.ActiveId.value);
        if (ActiveRule._parent && this.RuleMapping[ActiveRule._parent]) {
            this.ActiveId.value = this.RuleMapping[ActiveRule._parent].field
        }
    }

    /**
     * 快捷键 选择子集
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeySelectChild() {
        if (this.CheckInputFocusStatus()) return;
        if (!this.ActiveId) return;
        const ActiveRule = this.GetRuleById(this.ActiveId.value);
        if (ActiveRule?.slots?.default && ActiveRule?.slots?.default[0] && ActiveRule?.slots?.default[0]?.field) {
            this.ActiveId.value = ActiveRule?.slots?.default[0]?.field
        }
    }

    /**
     * 快捷键 想左选择兄级
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeySelectLeft() {
        if (this.CheckInputFocusStatus()) return;
        if (!this.ActiveId) return;
        const AId = this.ActiveId.value;
        const ActiveRule = this.GetRuleById(AId);
        if (ActiveRule._parent && this.RuleMapping[ActiveRule._parent]) {
            const parent = this.RuleMapping[ActiveRule._parent];
            const arr = parent.slots[ActiveRule._slotkey];
            let index = null;
            for (let i = 0; i < arr.length; i++) {
                const element = arr[i];
                if (element.field == AId) {
                    index = i;
                    break;
                }
            };
            if (index !== 0 && index !== null) {
                this.ActiveId.value = arr[index - 1].field;
            }
        }
    }

    /**
     * 快捷键 向右选择兄级
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeySelectRight() {
        if (this.CheckInputFocusStatus()) return;
        if (!this.ActiveId) return;
        const AId = this.ActiveId.value;
        const ActiveRule = this.GetRuleById(AId);
        if (ActiveRule._parent && this.RuleMapping[ActiveRule._parent]) {
            const parent = this.RuleMapping[ActiveRule._parent];
            const arr = parent.slots[ActiveRule._slotkey];
            let index = null;
            for (let i = 0; i < arr.length; i++) {
                const element = arr[i];
                if (element.field == AId) {
                    index = i;
                    break;
                }
            };
            if ((index !== arr.length - 1) && index !== null) {
                this.ActiveId.value = arr[index + 1].field;
            }
        }
    }

    /**
     * 快捷键 删除
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    HotKeyDelete() {
        if (this.CheckInputFocusStatus()) return;
        if (!this.ActiveId) return;
        const AId = this.ActiveId.value;
        AId && this.DeleteItem(AId);
    }
    /**
     * 根据 ID 获取类型配置文件
     *
     * @param {string} val
     * @return {*} 
     * @memberof DocumentEditor
     */
    GetRuleConfigById(val: string) {
        const Type = this.GetRuleById(val).type;
        return this.GetRuleType(Type)
    }
    /**
     * 根据类型,获取元件配置文件参数
     *
     * @param {string} type
     * @return {*} 
     * @memberof DocumentEditor
     */
    GetRuleType(type: string) {
        return this.Rules[type]?.Rule
    }

    /**
     * 根据 id 获取元件配置
     *
     * @param {string} val
     * @return {*} 
     * @memberof DocumentEditor
     */
    GetRuleById(val: string) {
        return this.RuleMapping[val]
    }

    /**
     * 缓存元件树
     *
     * @param {string} id
     * @param {*} val
     * @memberof DocumentEditor
     */
    SetCellById(id, val) {
        this.CellMapping[id] = val;
    }

    /**
     * 根据ID 获取元件实例化对象(Vue export对象)
     *
     * @param {*} val
     * @return {*} 
     * @memberof DocumentEditor
     */
    GetCellById(val) {
        return this.CellMapping[val]
    }

    /**
     * 向上遍历父级元素
     *
     * @param {*} Rule
     * @param {Function} cellback
     * @memberof DocumentEditor
     */
    EachParent(Rule, cellback: Function) {
        const parentId = Rule._parent;
        if (parentId) {
            const parent = this.GetRuleById(parentId);
            const isbreak = cellback(parent);
            if (isbreak !== false) {
                this.EachParent(parent, cellback)
            }
        }
    }
    Save() {
        // 待开发:当属性值等于默认值时, 删除属性值, 以减小JSON体积

    }
    Preview() { }

    /**
     * 注销组件
     *
     * @return {*} 
     * @memberof DocumentEditor
     */
    destroy() {
        this.MouseEvent && this.MouseEvent.destroy();
        this.Hotkey && this.Hotkey.destroy();
        this.HistoryEvent && this.HistoryEvent.destroy();

        if (!this) return;
        this.CellMapping = null;
        this.RuleMapping = null;
        this.WillUploadFileMapping = null
        this.ParentList = null;
        this.ActiveRect = null;
        this.ActiveId = null;
        this.HoverRect = null;
        this.HoverItemId = null;
        for (let i = 0; i < this.WatchCache.length; i++) {
            const element = this.WatchCache[i];
            element();
        }
        this.WatchCache = null;
    }




    RunAction() { }
}
